# ----------说明----------
# 功能：
# 1，通过esp32-s3的uart1串口与读卡器模块通信，给读卡器模块写入配置指令，读取读卡器的输出数据（其中包括卡id）
# 2，tx=12, rx=11，gpio1=reader_led读取电平高低以判断tag进入or离开
# 3,通过mqtt将数据传到服务器
#修改日志：1，20250501yangli，完成1，2，3
# ----------说明----------

from machine import UART, Pin
import network
import time
import ntptime
import ujson
import json
from machine import Pin, SoftI2C, UART
from machine import WDT
import gc
from umqttsimple import MQTTClient

softver='20250506 v5.6'
print('softversion=:',softver)

# chat建议模块，初始化看门狗定时器，设置超时时间为10秒
wdt = WDT(timeout=10000)  # 超时时间单位是毫秒 (10秒)

#chat建议的清除中断设置，
try:
    int_pin.irq(handler=None)
except:
    pass


# ----------联网配置----------
ssid = 'Xiaomi_VICTOR_2.4G'
key = '31415926victor'

def do_connect():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('正在连接...')
        wlan.connect(ssid, key)
        while not wlan.isconnected():
            pass
    print('网络已连接:', wlan.ifconfig())

do_connect()

# ----------获取北京时间模块----------
time_offset = 8 * 60 * 60  # 东八区

def sync_time(retry_count=5, retry_delay=1):
    for attempt in range(retry_count):
        try:
            ntptime.settime()
            print("NTP时间同步成功")
            return True
        except Exception as e:
            print(f"尝试 {attempt + 1}/{retry_count} 同步失败：{e}")
            if attempt < retry_count - 1:
                print(f"等待 {retry_delay} 秒后重新尝试...")
                time.sleep(retry_delay)
            else:
                print("已达到最大重试次数，时间同步失败")
                return False  # 如果超过最大重试次数仍失败，则返回False            
def get_beijing_time():
    t = time.localtime(time.time() + time_offset)
    ms = time.ticks_ms() % 1000
    return "{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}".format(*t[:6], ms)

sync_time()
last_sync = time.time()
SYNC_INTERVAL = 600  # 每10分钟同步一次


def send_command(command_bytes):
    print("发送命令:", command_bytes.hex())
    uart.write(command_bytes)
    time.sleep(0.1)
    response = uart.read()
    if response:
        print("收到响应:", response.hex())
    else:
        print("未收到响应")
    return response                                   


# 初始化UART（ESP32-S3的TX=12，RX=11）
uart = UART(1, baudrate=19200, bits=8, parity=1, stop=1, tx=12, rx=11)


clear_command=bytes.fromhex("00 06 00 02 00 00 29 DB")
send_command(clear_command)


# 配置线圈启动
read_info_cmd = bytes.fromhex("03 03 00 01 00 04 14 2B")  # 正确CRC
send_command(read_info_cmd)


#ttl_set_command=bytes.fromhex("03 06 00 64 00 40 C9 DF ")
#send_command(ttl_set_command)

#主动连续上传模式
# auto_read_cmd = bytes.fromhex("03 06 00 00 00 07 C9 EA")  # 正确CRC
# send_command(auto_read_cmd)

# 主动不连续上传模式
auto_read_cmd = bytes.fromhex("03 06 00 00 00 03 C8 29")  # 正确CRC
send_command(auto_read_cmd)

# 被动上传模式
#初始化后的默认状态
client = MQTTClient("umqtt_client", "192.168.31.216")  # 建立一个MQTT客户端
client.connect()  # 建立连接
mqtt_topic="reader_to_cpter"
# 发送消息到MQTT
def mqtt_publish(client, mqtt_topic, message):
    try:
        client.publish(mqtt_topic, message)
        print('已发送数据:', message)
    except Exception as e:
        print('发送数据失败:', e)
        try:
            client.disconnect()
            client.connect()
        except Exception as e2:
            print("MQTT重连失败:", e2)

mqtt_publish(client, mqtt_topic, softver)
reader_ID = 1  # 当前只有一个读卡器，ID为1
reader_led = Pin(1, Pin.IN)  # GPIO1 读取 LED 电平状态（低=无卡，高=有卡）
last_led_state = reader_led.value()
in_recording = False  # 是否处于进入记录阶段
enter_time = None
mouse_ID = None
while True:
    wdt.feed()  # 喂狗
    gc.collect()  # 垃圾回收
#     uart.read()  # 清空缓存
#     time.sleep(0.006)
    now = time.time()
    if now - last_sync >= SYNC_INTERVAL:
        sync_time()
        last_sync = now
    current_led = reader_led.value()
    if current_led != last_led_state:
        # 电平发生变化
        timestamp = get_beijing_time()
        if current_led == 0 and not in_recording:
            enter_time = timestamp
            print("[{}] 有老鼠进入，读取卡号...".format(enter_time))
            in_recording = True
            
            response = uart.read()
            wdt.feed()
            if response and len(response) >= 10:
                print("读卡器响应：", response.hex())
                try:
                    mouse_ID = response[5:10].hex().upper()
                    print("识别到老鼠ID:", mouse_ID)
                except Exception as e:
                    print("卡号解析失败",e)
                    mouse_ID = "UNKNOWN"
            else:
                print("未读取到卡号或响应长度不足")
                mouse_ID = "UNKNOWN"
        elif current_led == 1 and in_recording:
            # 低电平，tag离开
            leave_time = timestamp
            print("[{}] 老鼠离开".format(leave_time))
            r = {
                "reader_ID": reader_ID,
                "enter_time": enter_time,
                "mouse_ID": mouse_ID,
                "leave_time": leave_time,
            }

            
            print('记录完成：{{"reader_ID": {}, "enter_time": "{}", "mouse_ID": "{}", "leave_time": "{}"}}'.format(
    reader_ID, enter_time, mouse_ID, leave_time))
            msg = ujson.dumps(r) 
            mqtt_publish(client, mqtt_topic, msg.encode()) 

            in_recording = False
            enter_time = None
            mouse_ID = None
        last_led_state = current_led       

    time.sleep(0.1)  # 缩短循环延迟


